package com.yunyun400.vosk.service;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.file.Files;
import java.nio.file.Path;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import org.vosk.Model;
import org.vosk.Recognizer;

import com.yunyun400.vosk.components.VoskModelManager;
import com.yunyun400.vosk.util.FfmpegUtil;
import com.yunyun400.vosk.util.Language;

@Service
public class SpeechService {

	
	@Autowired
	private FfmpegUtil ffmpegUtil;
	
	@Autowired
    private VoskModelManager voskModelManager; // 注入新的模型管理器

    /**
     * 处理本地MP3文件并返回识别结果
     * @param mp3File MP3文件
     * @param language 语言选择
     * @return 识别出的文本
     * @throws Exception 如果转换或识别过程中发生错误
     */
    public String recognizeSpeechFromFile(File mp3File, Language language) throws Exception {
        // 创建临时目录来存放转换后的 PCM 文件
        Path tempDir = Files.createTempDirectory("vosk-pcm-");
        File tempPcmFile = new File(tempDir.toFile(), "output.pcm");

        try {
            // 使用 FFmpeg 将 MP3 转换为 PCM
            ffmpegUtil.convertMp3ToPcm(mp3File.getAbsolutePath(), tempPcmFile.getAbsolutePath());
            System.out.println("FFmpeg 转换完成，PCM 文件保存到: " + tempPcmFile.getAbsolutePath());

            // 从模型管理器中获取指定语言的模型
            Model model = voskModelManager.getModel(language);
            if (model == null) {
                throw new RuntimeException("无法获取 " + language + " 的 Vosk 模型。");
            }
            
            // 使用 Vosk 识别 PCM 文件
            String result = recognizePcmFile(tempPcmFile, model);
            return result;

        } finally {
            // 清理临时文件和目录
            Files.deleteIfExists(tempPcmFile.toPath());
            Files.deleteIfExists(tempDir);
            System.out.println("临时PCM文件已清理。");
        }
    }
    
    /**
     * 使用 Vosk 识别单个 PCM 文件。
     * @param pcmFile PCM 文件。
     * @return 识别结果。
     * @throws IOException 如果文件读取失败。
     */
    private String recognizePcmFile(File pcmFile, Model model) throws IOException {
        try (Recognizer recognizer = new Recognizer(model, 16000.0f)) {
            try (FileInputStream fis = new FileInputStream(pcmFile)) {
                byte[] buffer = new byte[4096];
                int bytesRead;
                StringBuilder finalResult = new StringBuilder();

                while ((bytesRead = fis.read(buffer)) != -1) {
                    // Vosk 需要 16-bit little-endian 的 PCM 数据
                    ByteBuffer byteBuffer = ByteBuffer.wrap(buffer, 0, bytesRead);
                    byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
                    short[] shorts = new short[bytesRead / 2];
                    byteBuffer.asShortBuffer().get(shorts);

                    if (recognizer.acceptWaveForm(shorts, shorts.length)) {
                        finalResult.append(recognizer.getResult()).append(",");
                    }
                }
                // 获取最后剩余的识别结果
                finalResult.append(recognizer.getFinalResult());
                return finalResult.toString();
            }
        }
    }
}
